﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WebViewerTest.NativeMethods;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Windows;
using System.Runtime.InteropServices.ComTypes;

namespace WebViewerTest
{
	public class WinFormsWebBrowser : Form, INotifyPropertyChanged, IMessageFilter, IAdviseSink
	{
		public event EventHandler ViewChanged;

		private WebBrowser browser;
		private IViewObject view;
//		public event EventHandler Changed;

		public WinFormsWebBrowser()
		{
			Enabled = false;
			Opacity = 0;
			StartPosition = FormStartPosition.Manual;

			browser = new WebBrowser();
			browser.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom;
			browser.Margin = new Padding( 0 );
			Controls.Add( browser );

			browser.ProgressChanged += delegate( object sender, WebBrowserProgressChangedEventArgs e )
			{
				SetProgress( (double)e.CurrentProgress / (double)e.MaximumProgress );
			};

			browser.DocumentCompleted += delegate
			{
				SetProgress( 0 );
			};

			browser.Navigated += delegate
			{
				if ( view == null )
				{
					view = browser.Document.DomDocument as IViewObject;
					view.SetAdvise( 1, 0, this );
				}
			};

			Enabled = true;
			System.Windows.Forms.Application.AddMessageFilter( this );
		}

		public double Progress { get; private set; }
		public Rect ProgressRect { get { return new Rect( 0, 0, Progress, 1 ); } }

		public Uri Url
		{
			get { return browser.Url; }
			set
			{
				browser.Url = value;
				SetProgress( 0 );
			}
		}
/*
		public override bool PreProcessMessage( ref Message msg )
		{
			if ( msg.Msg == Win32.User32.WM_TIMER || msg.Msg == Win32.User32.WM_SETCURSOR )
			{
				if ( Changed != null ) Changed( this, EventArgs.Empty );
			}

			return base.PreProcessMessage( ref msg );
		}

		protected override void OnProgressChanged( WebBrowserProgressChangedEventArgs e )
		{
			brows

			browser.OnProgressChanged( e );
		}

		protected override void OnDocumentCompleted( WebBrowserDocumentCompletedEventArgs e )
		{

			base.OnDocumentCompleted( e );
		}
*/
		private void SetProgress( double progress )
		{
			Progress = Math.Max( 0, Math.Min( 1, progress ) );
			OnPropertyChanged( "Progress" );
			OnPropertyChanged( "ProgressRect" );
		}

		public IntPtr SendMouseDown( int x, int y )
		{
			return SendMouseMessage( Win32.User32.WM_LBUTTONDOWN, x, y );
		}

		public IntPtr SendMouseUp( int x, int y )
		{
			return SendMouseMessage( Win32.User32.WM_LBUTTONUP, x, y );
		}

		public IntPtr SendMouseMove( Point global, Point local )
		{
			this.Left = (int)( global.X - local.X );
			this.Top = (int)( global.Y - local.Y );

			var instance = browser.ActiveXInstance as IWebBrowser2;
			var window = instance.Document as IOleWindow;

			if ( window != null )
			{
				IntPtr hWnd;
				window.GetWindow( out hWnd );
//				Win32.User32.SetActiveWindow( hWnd );
				Win32.User32.SendMessage( hWnd, Win32.User32.WM_NCACTIVATE, 1, 0 );
			}
/*
			var input = new Win32.MOUSEINPUT { dwFlags = Win32.MOUSEEVENTF.ABSOLUTE | Win32.MOUSEEVENTF.MOVE, dx = x, dy = y };
			Win32.User32.SendInput( 1, new[] { new Win32.Input { mi = input } }, Marshal.SizeOf( typeof( Win32.Input ) ) );*/
			return (IntPtr)0;
//			return SendMouseMessage( Win32.User32.WM_MOUSEMOVE, x, y );
		}

		public IntPtr SendMouseMessage( uint message, int x, int y )
		{
			return SendMessage( message, (IntPtr)0, (IntPtr)(int)( ( y << 16 ) | ( x & 0xFFFF ) ) );
		}

		private IntPtr SendMessage( uint message, IntPtr wParam, IntPtr lParam )
		{
			var instance = browser.ActiveXInstance as IWebBrowser2;
			var window = instance.Document as IOleWindow;

			if ( window != null )
			{
				IntPtr hWnd;
				window.GetWindow( out hWnd );

				return Win32.User32.SendMessage( hWnd, message, wParam, lParam );
			}

			return (IntPtr)0;
		}

		#region INotifyPropertyChanged Members

		public event PropertyChangedEventHandler PropertyChanged;

		private void OnPropertyChanged( string propertyName )
		{
			if ( PropertyChanged != null ) PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
		}

		#endregion

		#region IMessageFilter Members

		bool IMessageFilter.PreFilterMessage( ref Message m )
		{
			switch ( m.Msg )
			{
				case Win32.User32.WM_ERASEBKGND:
				case Win32.User32.WM_PAINT:
					return false;

				default:
					return false;
			}
		}

		#endregion

		#region IAdviseSink Members

		void IAdviseSink.OnClose()
		{
			if ( view != null )
			{
				view.SetAdvise( 1, 0, null );
				view = null;
			}
		}

		void IAdviseSink.OnDataChange( ref FORMATETC format, ref STGMEDIUM stgmedium )
		{
		}

		void IAdviseSink.OnRename( IMoniker moniker )
		{
		}

		void IAdviseSink.OnSave()
		{
		}

		void IAdviseSink.OnViewChange( int aspect, int index )
		{
			if ( ViewChanged != null ) ViewChanged( this, EventArgs.Empty );
		}

		#endregion
	}
}